package com.itcast.tanhuaserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itcast.tanhuaserver.domain.*;
import com.itcast.tanhuaserver.enums.LevelEnum;
import com.itcast.tanhuaserver.mapper.*;
import com.itcast.tanhuaserver.service.SoulService;
import com.itcast.tanhuaserver.service.UserInfoService;
import com.itcast.tanhuaserver.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @PachageName: com.itcast.tanhuaserver.service.impl
 * @ClassName:
 * @Description: TODO
 * @Author: Hushi
 * @DateTime: 2021/3/119:27
 * @Version 1.0
 */
@Service
@Slf4j
public class SoulServiceImpl implements SoulService {

    @Autowired
    private SoulMapper soulMapper;

    @Autowired
    private Soul1Mapper soul1Mapper;

    @Autowired
    private QuestionsMapper questionsMapper;

    @Autowired
    private OptionMapper optionMapper;

    @Autowired
    private ReportMapper reportMapper;

    @Autowired
    private DimensionsMapper dimensionsMapper;

    @Autowired
    private UserInfoService userInfoService;

    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Value("${soul.maxQuestionLevel}")
    private Integer maxQuestionLevel;

    @Override
    public List<TestSoulVo> querySoulList(){
        //获取User对象
        User user = UserThreadLocal.get();
        //通过当前登录用户的Id从数据库中获取问卷集合
        QueryWrapper<Soul> query = new QueryWrapper<>();
        query.eq("user_id",user.getId());
        List<Soul> souls = this.soulMapper.selectList(query);
        if (CollectionUtils.isEmpty(souls)){
            return Collections.emptyList();
        }

        //定义返回对象
        List<TestSoulVo> soulVoList = new ArrayList<>();
        //遍历问卷集合
        for (Soul soul : souls) {
            //问卷的VO对象
            TestSoulVo soulVo = new TestSoulVo();
            //问卷问题集合
            List<QuestionsVo> questionsVoList = new ArrayList<>();
            //通过问卷Id查询当前问卷的问题集合
            QueryWrapper<Questions> questionsQuery = new QueryWrapper<>();
            //每个用户3条数据,每条对应一个问卷,问提表和问卷表关联的是soul.id(问题表只有1,2,3),
            questionsQuery.eq("sid", soul.getId() % 3 == 0? 3 : soul.getId() % 3);
            //遍历问题列表并赋值
            List<Questions> questions = this.questionsMapper.selectList(questionsQuery);
            if (!CollectionUtils.isEmpty(questions)){
                //遍历问题
                for (Questions question : questions){
                    //问题返回对象
                    QuestionsVo questionsVo = new QuestionsVo();
                    //定义选项集合
                    List<OptionsVo> optionsVoList = new ArrayList<>();
                    //根据qid查询选项
                    QueryWrapper<Option> optionQuery = new QueryWrapper<>();
                    optionQuery.eq("qid",question.getId());
                    List<Option> options = this.optionMapper.selectList(optionQuery);
                    //非空判断
                    if (!CollectionUtils.isEmpty(options)){
                        //遍历选项
                        for (Option option : options) {
                            //选项属性赋值
                            OptionsVo optionsVo = new OptionsVo();
                            optionsVo.setId(option.getId());
                            optionsVo.setOption(option.getOptionValue());
                            optionsVoList.add(optionsVo);
                        }
                    }
                    //问题属性赋值
                    questionsVo.setId(question.getId().toString());
                    questionsVo.setQuestion(question.getQuestion());
                    questionsVo.setOptions(optionsVoList);
                    questionsVoList.add(questionsVo);
                }
            }
            //问卷属性赋值
            soulVo.setId(soul.getId().toString());
            soulVo.setCover(soul.getCover());
            soulVo.setIsLock(soul.getIsLock());
            soulVo.setLevel(soul.getLevel());
            soulVo.setName(soul.getName());
            soulVo.setQuestions(questionsVoList);
            soulVo.setStar(Integer.parseInt(soul.getStar()));
            //报告ID判断非空,为空则不添加,不为空说明已经测试过此问卷了,可直接查看测试结果
            if (!StringUtils.isEmpty(soul.getReportId()) && soul.getReportId().length() > 0){
                soulVo.setReportId(soul.getReportId());
            }
            //添加问卷
            soulVoList.add(soulVo);
        }
        return soulVoList;
    }

    /**
     * 提交问卷选项得到报告
     * @param answers
     * @return
     */
    @Override
    public String importSoulTest(List<Answers> answers) {
        //获取userId
        User user = UserThreadLocal.get();
        try {
            //判断是那一级别的题目,默认为初级
            String level = "初级";
            //随便获取一个问题,问题集合属于同一个问题级别,通过questionId来获取问题的级别,方便后台添加或减少问题,不写死
            String questionId = answers.get(0).getQuestionId();
            QueryWrapper<Questions> queryQuestion = new QueryWrapper<>();
            queryQuestion.eq("id",questionId);
            Questions question = this.questionsMapper.selectOne(queryQuestion);
            level = question.getName();

            //循环结果,开始计分
            Integer score = 0;
            for (Answers answer : answers) {
                //通过问题Id和选项Id得到当前选项的分数
                QueryWrapper<Option> query = new QueryWrapper<>();
                query.eq("id",answer.getOptionId());
                query.eq("qid",answer.getQuestionId());
                Option option = this.optionMapper.selectOne(query);
                //加分
                score += option.getScore();
            }

            //查询报告列表
            List<Report> reportList = this.reportMapper.selectList(new QueryWrapper<>());
            //循环判断该分数属于哪一个报告
            for (Report report : reportList) {
                if (score <= report.getMax() && score >= report.getMin()){
                    //修改当前问卷状态(当前用户的问卷报告Id,解锁下一级问卷)
                    //return this.updateSoulStatus(report.getId().toString(),user.getId().longValue(),level);
                    return this.updateSoulStatus1(report.getId().toString(),user.getId().longValue(),level);
                }
            }
        } catch (NumberFormatException e) {
            log.error("提交问卷错误~ userid=" + user.getId(),e);
        }
        //返回默认的报告Id
        return "1";
    }


    //修改当前问卷状态(当前用户的此问卷报告Id,是否需要解锁下一级问卷)
    private String updateSoulStatus(String reportId,Long userId,String level){
        try{
            Soul soul = new Soul();
            //设置报告Id
            soul.setReportId(reportId);

            //根据等级和用户Id得到问卷的条件
            UpdateWrapper<Soul> query = new UpdateWrapper<>();
            query.eq("level",level);
            query.eq("user_id",userId);
            //查询当前问卷的问卷Id
            Integer id = this.soulMapper.selectOne(query).getId();
            //通过配置文件设置最大级别个数,取余为0说明到了最大级别,增强灵活性和可修改
            if (id % maxQuestionLevel == 0){
                //最大级别(高级)只需要修改问卷的报告Id
                this.soulMapper.update(soul,query);
            }else{
                //不是最大级别的(中级/初级)除了修改问卷Id,还需要解锁下一级别
                this.soulMapper.update(soul,query);
                //解锁下一级问卷设置
                Soul soulLock = new Soul();
                soulLock.setIsLock(0);
                //条件为当前用户和问卷id+1(中级/高级)
                UpdateWrapper<Soul> queryLoke = new UpdateWrapper<>();
                queryLoke.eq("user_id",userId);
                queryLoke.eq("id",id + 1);
                //解锁
                this.soulMapper.update(soulLock,queryLoke);
            }
        }
        catch(Exception e){
            log.error("提交问卷的修改当前问卷状态错误 ~ userId=" + userId + ", level=" + level + ", reportId" + reportId,e);
        }
        return reportId;
    }

    //修改当前问卷状态(当前用户的此问卷报告Id,是否需要解锁下一级问卷)
    private String updateSoulStatus1(String reportId,Long userId,String level){
        try{
            Soul1 soul = new Soul1();
            switch (level){
                case "初级":
                    //设置报告Id和下一级解锁
                    soul.setReportId(reportId);
                    soul.setIsLock1(0);
                    break;
                case "中级":
                    soul.setReportId1(reportId);
                    soul.setIsLock2(0);
                    break;
                case "高级":
                    soul.setReportId2(reportId);
                    break;
            }
            QueryWrapper<Soul1> query = new QueryWrapper<>();
            query.eq("user_id",userId);
            this.soul1Mapper.update(soul,query);
        }
        catch(Exception e){
            log.error("提交问卷的修改当前问卷状态错误 ~ userId=" + userId + ", level=" + level + ", reportId" + reportId,e);
        }
        return reportId;
    }

    /**
     * 查看结果,根据闹高Id返回
     * @param id
     * @return
     */
    @Override
    public SoulResultVo queryReportById(String id) {
        //获取User对象
        User user = UserThreadLocal.get();
        //定义返回结果的VO对象
        SoulResultVo soulResultVo = new SoulResultVo();
        //根据报告Id查询报告对象(id,内容,图片封面)并赋值
        Report report = this.reportMapper.selectById(id);
        soulResultVo.setConclusion(report.getReport());
        soulResultVo.setCover(report.getCover());

        //设置返回的维度对象(外向,判断,抽象,理性);
        //根据报告Id获取(每个报告对象对应一个维度对象)
        QueryWrapper<Dimensions> query = new QueryWrapper<>();
        query.eq("rid",id);
        Dimensions dimensions = this.dimensionsMapper.selectOne(query);
        //给维度属性赋值,列如 : 外向:80% ...
        List<DimensionsVo> dimensionsVoList = new ArrayList<>();
        dimensionsVoList.add(new DimensionsVo("外向",dimensions.getKey1()));
        dimensionsVoList.add(new DimensionsVo("判断",dimensions.getKey2()));
        dimensionsVoList.add(new DimensionsVo("抽象",dimensions.getKey3()));
        dimensionsVoList.add(new DimensionsVo("理性",dimensions.getKey4()));
        //赋值维度集合
        soulResultVo.setDimensions(dimensionsVoList);

        //与你相似 : 查询报告Id有一样的用户
        //根据报告此Id查询问卷列表
        QueryWrapper<Soul> querySoulList = new QueryWrapper<>();
        querySoulList.eq("report_id",id);
        List<Soul> souls = this.soulMapper.selectList(querySoulList);
        //定义UserId集合
        List<Long> userIds = new ArrayList<>();
        //循环问卷
        for (Soul soul : souls) {
            //是自己且集合中已经有的不添加
            if (soul.getUserId() != user.getId().longValue() && !userIds.contains(soul.getUserId())){
                userIds.add(soul.getUserId());
            }
        }
        //非空判断
        if (!CollectionUtils.isEmpty(userIds)){
            //根据Id查询UserInfo的信息
            QueryWrapper<UserInfo> queryUserInfo = new QueryWrapper<>();
            queryUserInfo.in("user_id",userIds);
            List<UserInfo> userInfos = this.userInfoService.queryUserInfoList(queryUserInfo);
            //定义 与你相似对象 集合
            List<SimilarYouVo> similarYouVoList = new ArrayList<>();
            for (UserInfo userInfo : userInfos) {
                //赋值,userId,头像
                SimilarYouVo similarYouVo = new SimilarYouVo();
                similarYouVo.setAvatar(userInfo.getLogo());
                similarYouVo.setId(userInfo.getUserId().intValue());
                similarYouVoList.add(similarYouVo);
            }
            //赋值 与你相似
            soulResultVo.setSimilarYou(similarYouVoList);
        }
        return soulResultVo;
    }


    /**
     * 查看结果,根据闹高Id返回
     * @param id
     * @return
     */
    @Override
    public SoulResultVo queryReportById1(String id) {
        //获取User对象
        User user = UserThreadLocal.get();
        //定义返回结果的VO对象
        SoulResultVo soulResultVo = new SoulResultVo();
        //根据报告Id查询报告对象(id,内容,图片封面)并赋值
        Report report = this.reportMapper.selectById(id);
        soulResultVo.setConclusion(report.getReport());
        soulResultVo.setCover(report.getCover());

        //设置返回的维度对象(外向,判断,抽象,理性);
        //根据报告Id获取(每个报告对象对应一个维度对象)
        QueryWrapper<Dimensions> query = new QueryWrapper<>();
        query.eq("rid",id);
        Dimensions dimensions = this.dimensionsMapper.selectOne(query);
        //给维度属性赋值,列如 : 外向:80% ...
        List<DimensionsVo> dimensionsVoList = new ArrayList<>();
        dimensionsVoList.add(new DimensionsVo("外向",dimensions.getKey1()));
        dimensionsVoList.add(new DimensionsVo("判断",dimensions.getKey2()));
        dimensionsVoList.add(new DimensionsVo("抽象",dimensions.getKey3()));
        dimensionsVoList.add(new DimensionsVo("理性",dimensions.getKey4()));
        //赋值维度集合
        soulResultVo.setDimensions(dimensionsVoList);

        //与你相似 : 查询报告Id有一样的用户
        //根据报告此Id查询问卷列表
        QueryWrapper<Soul1> querySoulList = new QueryWrapper<>();
        querySoulList.eq("report_id",id).or().eq("report_id1",id).or().eq("report_id2",id);
        List<Soul1> souls = this.soul1Mapper.selectList(querySoulList);
        //定义UserId集合
        List<Long> userIds = new ArrayList<>();
        //循环问卷
        for (Soul1 soul : souls) {
            //是自己且集合中已经有的不添加
            if (soul.getUserId() != user.getId().longValue() && !userIds.contains(soul.getUserId())){
                userIds.add(soul.getUserId());
            }
        }
        //非空判断
        if (!CollectionUtils.isEmpty(userIds)){
            //根据Id查询UserInfo的信息
            QueryWrapper<UserInfo> queryUserInfo = new QueryWrapper<>();
            queryUserInfo.in("user_id",userIds);
            List<UserInfo> userInfos = this.userInfoService.queryUserInfoList(queryUserInfo);
            //定义 与你相似对象 集合
            List<SimilarYouVo> similarYouVoList = new ArrayList<>();
            for (UserInfo userInfo : userInfos) {
                //赋值,userId,头像
                SimilarYouVo similarYouVo = new SimilarYouVo();
                similarYouVo.setAvatar(userInfo.getLogo());
                similarYouVo.setId(userInfo.getUserId().intValue());
                similarYouVoList.add(similarYouVo);
            }
            //赋值 与你相似
            soulResultVo.setSimilarYou(similarYouVoList);
        }
        return soulResultVo;
    }


    /*
        返回问卷列表
     */
    @Override
    public List<TestSoulVo> querySoulList1() {
        //获取User对象
        User user = UserThreadLocal.get();
        //定义返回对象
        List<TestSoulVo> result = new ArrayList<>();
        try {
            //先从redis获取,redis命中则给返回对象赋值,没有命中则从mysql获取
            String redisKey = "SOULFORM_" + user.getId();
            if (this.redisTemplate.hasKey(redisKey)){
                result = MAPPER.readValue(this.redisTemplate.opsForValue().get(redisKey), List.class);
            }
            else{
                //通过当前登录用户的Id从数据库中获取问卷集合
                QueryWrapper<Soul> query = new QueryWrapper<>();
                query.eq("user_id",user.getId());
                List<Soul> souls = this.soulMapper.selectList(query);
                if (CollectionUtils.isEmpty(souls)){
                    //没有此用户,一般不会出现此问题
                    return Collections.emptyList();
                }

                //循环遍历问卷列表并赋值
                for (Soul soul : souls) {
                    //问卷的VO对象
                    TestSoulVo soulVo = new TestSoulVo();
                    //问题集合
                    List<QuestionsVo> questionsVoList = new ArrayList<>();
                    //通过问卷Id查询当前问卷的问题集合
                    QueryWrapper<Questions> questionsQuery = new QueryWrapper<>();
                    questionsQuery.eq("name",soul.getName());
                    List<Questions> questions = this.questionsMapper.selectList(questionsQuery);
                    //非空判断,正常情况必不可能出空集合
                    if (!CollectionUtils.isEmpty(questions)){
                        //遍历问题列表并赋值
                        for (Questions question : questions){
                            //定义问题的VO对象
                            QuestionsVo questionsVo = new QuestionsVo();
                            //问题的选项集合
                            List<OptionsVo> optionsVoList = new ArrayList<>();
                            //通过问题的Id得到此问题对应的选项集合
                            QueryWrapper<Option> optionQuery = new QueryWrapper<>();
                            optionQuery.eq("qid",question.getId());
                            List<Option> options = this.optionMapper.selectList(optionQuery);
                            //非空判断
                            if (!CollectionUtils.isEmpty(options)){
                                //遍历选项VO对象,并赋值
                                for (Option option : options) {
                                    OptionsVo optionsVo = new OptionsVo();
                                    //选项属性赋值
                                    optionsVo.setId(option.getId());
                                    optionsVo.setOption(option.getOptionValue());
                                    optionsVoList.add(optionsVo);
                                }
                            }
                            //问题属性赋值
                            questionsVo.setId(question.getId().toString());
                            questionsVo.setQuestion(question.getQuestion());
                            questionsVo.setOptions(optionsVoList);
                            questionsVoList.add(questionsVo);
                        }
                    }
                    //问卷属性赋值
                    soulVo.setId(soul.getId().toString());
                    soulVo.setCover(soul.getCover());
                    soulVo.setIsLock(soul.getIsLock());
                    soulVo.setLevel(soul.getLevel());
                    soulVo.setName(soul.getName());
                    soulVo.setQuestions(questionsVoList);
                    soulVo.setStar(Integer.parseInt(soul.getStar()));
                    //报告ID判断非空,为空则不添加,不为空说明已经测试过此问卷了,可直接查看测试结果
                    if (!StringUtils.isEmpty(soul.getReportId()) && soul.getReportId().length() > 0){
                        soulVo.setReportId(soul.getReportId());
                    }
                    //添加当前问卷对象
                    result.add(soulVo);
                }
                //将问卷列表存入redis中,减轻mysql压力,存储1天
                this.redisTemplate.opsForValue().set(redisKey,MAPPER.writeValueAsString(result),24, TimeUnit.HOURS);
            }
        } catch (IOException e) {
            log.error("返回问卷列表错误~",e);
        }
        //返沪结果
        return result;
    }


    /**
     * 数据库表优化后的接口
     * @return
     */
    @Override
    public List<TestSoulVo> querySoulList2(){
        //获取User对象
        User user = UserThreadLocal.get();
        //通过当前登录用户的Id从数据库中获取问卷集合
        QueryWrapper<Soul1> query = new QueryWrapper<>();
        query.eq("user_id",user.getId());
        //获取查询出来的用户试卷
        Soul1 soul1 = this.soul1Mapper.selectOne(query);
        if (StringUtils.isEmpty(soul1)){
            soul1 = new Soul1(
                    "初级灵魂题","https://tanhua-dev.oss-cn-zhangjiakou.aliyuncs.com/images/test_soul/qn_cover_01.png","初级",2,0,"",
                    "中级灵魂题","https://tanhua-dev.oss-cn-zhangjiakou.aliyuncs.com/images/test_soul/qn_cover_02.png","中级",3,1,"",
                    "高级灵魂题","https://tanhua-dev.oss-cn-zhangjiakou.aliyuncs.com/images/test_soul/qn_cover_03.png","高级",5,1,"",
                    user.getId().longValue()
            );
            this.soul1Mapper.insert(soul1);
        }
        //定义返回对象
        List<TestSoulVo> soulVoList = new ArrayList<>();

        //问卷的VO对象
        TestSoulVo soulVo1 = new TestSoulVo();
        soulVo1.setId("初级");
        setSoulValue(soulVo1,soul1);

        TestSoulVo soulVo2 = new TestSoulVo();
        soulVo2.setId("中级");
        setSoulValue(soulVo2,soul1);

        TestSoulVo soulVo3 = new TestSoulVo();
        soulVo3.setId("高级");
        setSoulValue(soulVo3,soul1);

        soulVoList.add(soulVo1);
        soulVoList.add(soulVo2);
        soulVoList.add(soulVo3);

        return soulVoList;
    }

    private void setSoulValue(TestSoulVo soulVo, Soul1 soul1) {
        switch (soulVo.getId()){
            case "初级":
                if (!StringUtils.isEmpty(soul1.getReportId()) && soul1.getReportId().length() > 0){
                    soulVo.setReportId(soul1.getReportId());
                }
                soulVo.setName(soul1.getName());
                soulVo.setLevel(soul1.getLevel());
                soulVo.setIsLock(soul1.getIsLock());
                soulVo.setCover(soul1.getCover());
                soulVo.setStar(soul1.getStar());
                soulVo.setQuestions(queryQuestionList(soul1.getLevel()));
                break;
            case "中级":
                if (!StringUtils.isEmpty(soul1.getReportId1()) && soul1.getReportId1().length() > 0){
                    soulVo.setReportId(soul1.getReportId1());
                }
                soulVo.setName(soul1.getName1());
                soulVo.setLevel(soul1.getLevel1());
                soulVo.setIsLock(soul1.getIsLock1());
                soulVo.setCover(soul1.getCover1());
                soulVo.setStar(soul1.getStar1());
                soulVo.setQuestions(queryQuestionList(soul1.getLevel1()));
                break;
            case "高级":
                if (!StringUtils.isEmpty(soul1.getReportId2()) && soul1.getReportId2().length() > 0){
                    soulVo.setReportId(soul1.getReportId2());
                }
                soulVo.setName(soul1.getName2());
                soulVo.setLevel(soul1.getLevel2());
                soulVo.setIsLock(soul1.getIsLock2());
                soulVo.setCover(soul1.getCover2());
                soulVo.setStar(soul1.getStar2());
                soulVo.setQuestions(queryQuestionList(soul1.getLevel2()));
                break;
        }
    }


    private List<QuestionsVo> queryQuestionList(String level) {
        List<QuestionsVo> questionsVoList = new ArrayList<>();
        QueryWrapper<Questions> questionsQuery = new QueryWrapper<>();
        questionsQuery.eq("name", level);
        //遍历问题列表并赋值
        List<Questions> questions = this.questionsMapper.selectList(questionsQuery);
        if (!CollectionUtils.isEmpty(questions)){
            //遍历问题
            for (Questions question : questions){
                //问题返回对象
                QuestionsVo questionsVo = new QuestionsVo();
                //定义选项集合
                List<OptionsVo> optionsVoList = new ArrayList<>();
                //根据qid查询选项
                QueryWrapper<Option> optionQuery = new QueryWrapper<>();
                optionQuery.eq("qid",question.getId());
                List<Option> options = this.optionMapper.selectList(optionQuery);
                //非空判断
                if (!CollectionUtils.isEmpty(options)){
                    //遍历选项
                    for (Option option : options) {
                        //选项属性赋值
                        OptionsVo optionsVo = new OptionsVo();
                        optionsVo.setId(option.getId());
                        optionsVo.setOption(option.getOptionValue());
                        optionsVoList.add(optionsVo);
                    }
                }
                //问题属性赋值
                questionsVo.setId(question.getId().toString());
                questionsVo.setQuestion(question.getQuestion());
                questionsVo.setOptions(optionsVoList);
                questionsVoList.add(questionsVo);
            }
        }
        return questionsVoList;
    }
}
